﻿
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SuperKit
{
    class ZipEach : CommandExecutor {
        public static string ZipExe => ConfigReader.Instance.ZipExe;
        public const string ZIP_DIR = "(_ZIP)";
        private FileContainer container;
        private string pwd;
        private int compressLevel;
        private bool isOverride;

        public ZipEach(ArgReader arg, IExecutorOwner form, string fpath) : base(arg, form, fpath) {
            
            pwd = arg.GetParameter("-pwd");
            compressLevel = arg.GetInteger("-level", 5);
            isOverride = arg.IsContain("-override");
        }


        public override void Execute() {
            Thread t = new Thread(OnProcess);
            t.Start();
        }

        private void OnProcess() {         
            var root = new DirectoryInfo(FilePath);
            container = new FileContainer(ZIP_DIR, root, Arg.TargetDir);
            var files = root.GetFiles();
            var dirs = root.GetDirectories();
            int total = Kit.Len(files) + Kit.Len(dirs);


            
            int pointer = 0;
            if (files != null) {
                foreach (var i in files) {
                    Flush($"处理文件[{pointer + 1}/{total}]: {i.Name}");
                    ProcessFile(i);
                    pointer++;
                }
            }
            if (dirs != null) {
                // 如果有ZIP_DIR，则要去掉项目
                foreach (var i in dirs) {
                    if (i.Name.Contains(ZIP_DIR)) {
                        total--;
                        break;
                    }
                }

                foreach (var i in dirs) {
                    if (i.Name.Contains(ZIP_DIR)) {
                        pointer++;
                        continue;
                    }

                    Flush($"处理目录[{pointer}/{total}]: {i.Name}");
                    ProcessDir(i);
                    pointer++;
                }
            }
            End();
        }

        private string PasswordTerm => (Kit.IsEmpty(pwd)) ? string.Empty : $" -p{pwd} ";
        private string CompressLevelTerm => $" -mx={compressLevel} ";

        private void ProcessDir(DirectoryInfo i) {
            var path = container.GetPath(i) + ".zip";
            if (Directory.Exists(path) && isOverride == false) {
                Flush($"目录已经存在：{path}");
                return;
            }
            string arg = $"a \"{path}\" {PasswordTerm} \"{i.FullName}\" {CompressLevelTerm}";
            //Flush(arg);
            ExecuteZip(arg);
        }

        private void ProcessFile(FileInfo i) {
            string path = container.GetDir(i, false) + ".zip";
            if (File.Exists(path) && isOverride == false) {
                Flush($"文件已经存在：{path}");
                return;
            }
            string arg = $"a \"{path}\" {PasswordTerm} \"{i.FullName}\" {CompressLevelTerm}";
            //Flush(arg);
            ExecuteZip(arg);
        }

        public string ExecuteZip(string cmd) {
            Process p = new Process();
            //设置要启动的应用程序
            p.StartInfo.FileName = ZipExe;
            p.StartInfo.Arguments = cmd;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.CreateNoWindow = true;

            p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler((SenderObject, EventArgs) => {
                string message = EventArgs.Data;
                SetStatus(message);
            });

            p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler((SenderObject, EventArgs) => {
                string message = EventArgs.Data;
                SetStatus(message);
            });

            p.Start();
            p.BeginErrorReadLine();
            p.WaitForExit();
            p.Close();

            return Kit.EMPTY;
        }

    }
}
